//
//  MZApi+Alamofire.swift
//  MZTool
//
//  Created by gby on 2023/2/7.
//

import Foundation
import Alamofire



public typealias MZSession = Alamofire.Session
internal typealias MZRequest = Alamofire.Request
internal typealias MZDownloadRequest = Alamofire.DownloadRequest
internal typealias MZUploadRequest = Alamofire.UploadRequest
internal typealias MZDataRequest = Alamofire.DataRequest

public typealias MZMethod = Alamofire.HTTPMethod

public typealias MZParameterEncoding = Alamofire.ParameterEncoding
public typealias MZJSONEncoding = Alamofire.JSONEncoding
public typealias MZURLEncoding = Alamofire.URLEncoding

public typealias MZDownloadDestination = Alamofire.DownloadRequest.Destination
public typealias RequestInterceptor = Alamofire.RequestInterceptor
public typealias MZRequestMultipartFormData = Alamofire.MultipartFormData



internal typealias MZRequestableCompletion = (HTTPURLResponse?, URLRequest?, Data?, Swift.Error?) -> Void


extension Request: MZRequestType {
    public var sessionHeaders: [String: String] {
        delegate?.sessionConfiguration.httpAdditionalHeaders as? [String: String] ?? [:]
    }
}

internal protocol MZRequestable {
    func response(callbackQueue: DispatchQueue?, completionHandler: @escaping MZRequestableCompletion) -> Self
}

extension MZDataRequest: MZRequestable {
    internal func response(callbackQueue: DispatchQueue?, completionHandler: @escaping MZRequestableCompletion) -> Self {
        if let callbackQueue = callbackQueue {
            return response(queue: callbackQueue) { handler  in
                completionHandler(handler.response, handler.request, handler.data, handler.error)
            }
        } else {
            return response { handler  in
                completionHandler(handler.response, handler.request, handler.data, handler.error)
            }
        }
    }
}

extension MZDownloadRequest: MZRequestable {
    internal func response(callbackQueue: DispatchQueue?, completionHandler: @escaping MZRequestableCompletion) -> Self {
        if let callbackQueue = callbackQueue {
            return response(queue: callbackQueue) { handler  in
                completionHandler(handler.response, handler.request, nil, handler.error)
            }
        } else {
            return response { handler  in
                completionHandler(handler.response, handler.request, nil, handler.error)
            }
        }
    }
}




public final class MZCancellableToken: MZCancellable, CustomDebugStringConvertible {
    let cancelAction: () -> Void
    let request: Request?

    public fileprivate(set) var isCancelled = false

    fileprivate var lock: DispatchSemaphore = DispatchSemaphore(value: 1)

    public func cancel() {
        _ = lock.wait(timeout: DispatchTime.distantFuture)
        defer { lock.signal() }
        guard !isCancelled else { return }
        isCancelled = true
        cancelAction()
    }

    public init(action: @escaping () -> Void) {
        self.cancelAction = action
        self.request = nil
    }

    init(request: Request) {
        self.request = request
        self.cancelAction = {
            request.cancel()
        }
    }
    public var debugDescription: String {
        guard let request = self.request else {
            return "Empty Request"
        }
        return request.cURLDescription()
    }

}



final class MZRequestInterceptor: RequestInterceptor {
    var prepare: ((URLRequest) -> URLRequest)?

    @MZAtomic
    var willSend: ((URLRequest) -> Void)?

    init(prepare: ((URLRequest) -> URLRequest)? = nil, willSend: ((URLRequest) -> Void)? = nil) {
        self.prepare = prepare
        self.willSend = willSend
    }

    func adapt(_ urlRequest: URLRequest, for session: Alamofire.Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
        let request = prepare?(urlRequest) ?? urlRequest
        willSend?(request)
        completion(.success(request))
    }
}
